/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
/*
 * bocciawii
 * Copyright (C) Grupo de trabajo ULE 2010 <ulewii@googlegroups.com>
 * 
 * bocciawii is free software: you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * bocciawii is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License along
 * with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef _PARTIDA_H_
#define _PARTIDA_H_

#include "render.h"
#include "error-log.h"
#include "mensaje.h"
#include "barra.h"
#include "linked-container.h"
#include "boton.h"
#include "screen-layout.h"
#include "menu-layout.h"
#include "elemento-estacionario.h"
#include "elemento-dinamico.h"
#include "input.h"
#include "equipo.h"
#include "bolas.h"


#include <cmath>
#include <stack>





#ifndef _SDL_H
#include "SDL.h"
#include "SDL_image.h"
#endif


#ifndef _GL_H
#include <GL/gl.h>
#include <GL/glu.h>
#endif

#define APP_NAME "BocciaWii"
#define APP_VERSION "0.1"
#define LOG_FILE "application_log.txt"

/**
 * @brief Estructura de nuestros estados
 *
 * Contiene el HUD activo, el menú activo, el tipo de estado
 * La posición desde la que se ha de mirar, y el tipo de cámara.
 */
typedef struct
{
	int estado;
	int camera_default;
	int box_camera;
	MenuLayout* menu;
	ScreenLayout* hud;
	long int duracion_milis;

} save_state;

/**
 * @brief Estructura de la puntuación
 *
 * Muy simple, dos campos <code>rojo</code> y <code>azul</code>: enteros para
 * las puntuaciones de cada equipo
 */
typedef struct
{
	int rojo;
	int azul;
} puntuacion;

/**
 * @brief Estructura del parcial del juego
 *
 * Estos campos son utilizados tanto como mantener una información "al día" del parcial
 * así como control acerca de la finalización del parcial y control de la bola blanca
 */
typedef struct
{
	int bolas_lanzadas;
	int finalizado;
	int bola_blanca_en_campo;
	int box_bola_blanca;
	int box_color;
	int perdidas_rojo;
	int perdidas_azul;
	puntuacion punt;
	ElementoDinamico* bola_blanca;
	// puntuacion y de qué equipo;
} parcial_boccia;

/**
 * @brief Estructura de una partida entera del juego
 * 
 * Estos campos son utilizados tanto como mantener una información "al día" del juego
 * así como control acerca de los parciales, la puntuación de cada uno, el número de jugadores
 * etcétera.
 */
typedef struct
{
	int nroParciales;
	int parcialActual;
	parcial_boccia *parcial; 
	int nroJugadores;
	int nroParcialesDes;
	puntuacion punt;
} juego_boccia;

/**
 * @brief Estructura de control acerca de la entrada del usuario
 *
 * Esta estructura será utilizada para saber cuántas bolas de cada tipo tiene cada jugador
 * y determinar un número máximo de las mismas
 */
typedef struct
{
	int box1[4];
	int box2[4];
	int box3[4];
	int box4[4];
	int box5[4];
	int box6[4];
	int bolas_por_box;
} control_entrada_juegos;

/**
 *  @brief Estructura que almacenará el puntero de nuestra aplicación
 *
 *  Información de control sobre posición, el "index" de la imagen a utilizar
 *   y todas las imágenes que componen el cursor.
 */
typedef struct
{
	int visible;
	int index;
	GLuint images[17];
	int x;
	int y;
} cursor_aplicacion;





/**
 * @brief Clase inicializadora y especialización en la lógica, física y elementos de la boccia
 *
 * La clase <code>Partida</code> es la clase que implementa las funciones propias del juego, 
 *  y lleva un control sobre la lógica y la física del mismo, los menús que se crean, el entorno que existirá, etcétera.
 * Registra todos los componentes finales (para esta aplicación en concreto) de <code>ElementoEstacionario</code>
 * <code>ElementoDinamico</code>, <code>MenuLayout</code>, etcétera que se usarán durante el juego.
 *
 * Sus miembros serán los que creen estos contenidos, ya sean menús, huds, modelos 3d, etcétera.
 *
 */
class Partida
{
public:
	/** 
	 * @brief Constructor simple, prepararlo todo para llegar al bucle de la aplicación
	 * 
	 *  Inicializar variables, introducir el primer estado, arrancar el input, y saltar al bucle de la aplicación
	 * @param opciones Las opciones cargadas del archivo de configuración
	 */
	Partida(opciones_aplicacion* opciones);

	~Partida();
protected:

private:
		
	// En partida.cc
	void Bucle();				/// Arranca el bucle de juego
		
	save_state EstadoCero();	/// Devuelve un estado con todos los valores inicializados adecuadamente
	void CambiaEstado();		/// Cambia al estado que se encuentra en la cima de la pila
								/// Establece menús, cámaras, etcéteras asociados al estado

	// Al menos para corregir las IDS en caso de que
	//  alguna estuviera mal, tenerlo separado en diferentes procedimientos
	//  en vez de buscar en 2000 líneas de código
	// En creacion_2d.cc
	void IniciaCursorMirada();  /// Inicia nuestro cursor, cargando sus imágenes.
	ScreenLayout* CargaHUD(int facesize);			/// Carga el hud principal de la aplicación
	MenuLayout* CargaMenuPpal();					/// Carga el menú principal (no sus submenús directamente)
	MenuLayout* CrearMenuJuego();					/// Crea el submenú de juego del menú principal
	MenuLayout* CrearMenuJuegoDos();				/// Crea el submenú de dos jugadores del menú de juego
	MenuLayout* CrearMenuJuegoSeis();				/// Crea el submenú de seis jugadores del menú de juego
	MenuLayout* CrearMenuOpciones();				/// Crea el submenú de opciones del menú principal
	MenuLayout* CrearMenuInGame();					/// Crea el menú In_game
	MenuLayout* CrearMenuSalir();					/// Crea el submenú de salida de aplicación utilizado en numeros menús
	MenuLayout* CrearMenuSeleccionBox();			/// Crea el submenú de selección de Box
	MenuLayout* CrearMenuSeleccionBola();			/// Crea el submenú de selección de bola
	MenuLayout* CrearMenuTamLetra();				/// Crea el submenú para elegir el tamaño de letra
	MenuLayout* CrearMenuEntradaJuego();			/// Crea el menú de la selección de bolas y boxes
	MenuLayout* CrearMenuEntradaBolasJuego();  		/// Crea el menú de la selección de bolas para un box (utilizará _boxActivo para controlarse)
	MenuLayout* CrearMenuEsperaParciales();			/// Crea el menú de espera entre parciales
	MenuLayout* CrearMenuEsperaFinal();				/// Crea el menú de espera del final del juego
	MenuLayout* CrearMenuEsperaConexion();			/// Crea el menú a mostrar en caso de desconexión
	MenuLayout* CrearMenuLanzamientoIncorrecto();   /// Crea el menú de lanzamiento incorrecto.

		

	// En creacion_entorno.cc
	void CargaEntorno();		/// Encapsula todos los procedimientos de carga de elementos estacionarios
	void CargaEstacionario(std::string ruta, int fijo = 0); /// Encapsula procedimientos comunes de carga 
	void CargaEstacionario(std::string ruta,				/// Establece además las posiciones y rotaciones iniciales
		 					float x, float y, float z,
							float rx, float ry, float rz, 
							 int fijo = 0 );

	// En dibujado.cc
	void DibujarEscena();						/// Encapsula los procedimientos de dibujado
	void EncolaEnRender();						/// Decide qué objetos estacionarios hay que dibujar
	void DibujarTrayectoria();					/// Dibuja la dirección en que la bola será lanzada
	void SetIndexCursor(desplazamiento des);	/// Elegirá la imagen que habrá de mostrarse en el cursor
	void DibujarCursor();						/// Dibujará el cursor
		
	// En eventos_callbacks.cc
	void ProcesarSeleccion(int selec);			/// Callbacks de eventos de selección
	void ProcesarCamara(desplazamiento des);	/// Callbacks de eventos de mirada
	void RealizaAccionesMenu(std::string seleccionado);		/// Callbacks para elementos del menú
	void ControlaEntradaJuego(std::string seleccionado);	/// Control de la entrada
	void ControlarSeleccionBox(std::string seleccionado);   /// Control de la entrada
	void ControlarSeleccionBola(std::string seleccionado);  /// Control de la entrada


	// En lógica.cc
	void InicializaJuego(int numero_jugadores); /// Arranca el juego, seteando equipos y bolas
	void InicializaBolasEquipos();				/// Asigna las bolas a los equipos
	void ProcesarLogica();
	void LogicaSubBlancaInvalida(int nroParcial);
	void LogicaSubBlancaValida(int nroParcial);
	void LogicaSubColorValido();
	void LogicaSubColorInvalido(int nroParcial, int box_seleccionado);
	void LogicaSubFinalComun(int nroParcial);
	void LogicaSubFinalParcial();
	void LogicaSubFinalJuego();
	void LogicaSubIniciarDesempate();
	void LogicaSubSetMenus(save_state ss, int nroParcial);

	// En modificacion_interfaces.cc
	void PrepararMenuBox();							// Prepara el menú del box dependiendo de equipo_que_lanza;
	void PrepararMenuBola();						// Prepara el menú de bolas dependiendo de _boxActivoMenu;
	void PrepararMenuPartida();						// Prepara el menú en función de control_entrada
	void PrepararMenuPartidaBola();					// Prepara el menú de comienzo de juego dependiendo de control_entrada
	void PrepararMenuEsperaParcial(int desempate);  // Prepara el menú entre parciales (asigna puntuaciones a mostrar)
	void PrepararMenuEsperaFinal();					// Prepara el menú de fin de juego(puntuaciones y resto de parciales)
	void ActualizaValoresEntrada();					// En el proceso de empezar un nuevo juego, asignará a cada menú los valores correctos

	int rotar; // Para saber si rotaremos el campo 180 grados

	
	ErrorLog* log;	  /// Nuestra clase para logs

	Render* render;	  /// Nuestro entorno de dibujado

	std::stack<save_state> pila_estados;	/// La pila de estados de la aplicación

	ElementoEstacionario* estacionario[60]; /// Nuestro entorno irá aquí (controlado con <code>num_estacionarios</code>)
	int num_estacionarios;					/// Contador de elementos en el entorno
	
	FTGLPixmapFont* font;					/// La fuente de los menús. Se usa una diferente ya que al tener imágenes (bastante autoexplicativas de la 
											///  funcionalidad ofrecida) ampliar demasiado el texto puede hacer que no se muestre correctamente.
	FTGLPixmapFont* fuente_hud;				/// La fuente del hud. Tamaño variable (desde opciones o fichero de configuración),	 
											///  el hud no tiene imágenes y así se solucionan posibles problemas para el visionado del mismo.

		
	// Los menús siempre referenciados, evitamos tiempos de carga entre estados, para un consumo mínimo
	// (en los tiempos que corren), de memoria.
	MenuLayout* menu_ppal;		/// Nuestro menú principal
	MenuLayout* menu_ingame;	/// El menú de la mitad del juego
	ScreenLayout* hud_ppal;		/// El hud principal
	MenuLayout* selbox;			/// El menú de selección de box (será modificado para ajustarlo a cada equipo)
	MenuLayout* selbola;		/// El menú de selección de bola (Será modificado para ajustarlo a cada box)
	MenuLayout* espera_parcial; /// El menú de espera entre parciales (puntuaciones)
	MenuLayout* espera_final;   /// El menú de espera en el final del juego (puntuacion final, y volver al menú principal)
	MenuLayout* desconexion;	/// El menú que aparecerá cuando no haya ningún mando conectado
	MenuLayout* incorrecto;		/// El menú que se mostrará cuando un lanzamiento sea inválido
	
	ScreenLayout* hud;  /// El hud activo que se modificará y mostrará la información actual
	MenuLayout* menu;   /// El menú activo, sobre el que se procesarán los eventos recibidos

	Input* input;	   /// Nuestro motor de eventos (tanto mando como SDL)

	opciones_aplicacion* _opciones;  // Las opciones de la aplicación
	
	int _boxActivoMenu;				// El box para el que se están eligiendo las bolas (sólo útil al comenzar un nuevo juego)

	cursor_aplicacion cursor_mirada;	// El cursor de la aplicación

	long int hud_ocultado;					/// Momento en el que se ocultó el HUD
	long int espera_mostrar_hud;			/// Tiempo a esperar para que se muestre el HUD desde que se deja de mirar en la aplicación. 
											///  Sirve para evitar "temblor" en el visor.
	long int antes;							/// Momento en el que se dibujó el último frame
	long int ahora;							/// Momento actual
	long int delta;							/// Delta de tiempo entre frames
	long int frecuencia;					/// Frecuencia de dibujado
		
	int tiempo_pasado;						/// Tiempo pasado desde que se detuvieron todas las bolas
											/// Detiene la ejecución un segundo para ver cómo han caído las bolas

	int done;								/// Variable de control para nuestro bucle

	juego_boccia juego_actual;				/// El juego actual
	control_entrada_juegos control_entrada; /// La entrada del menú

	Equipo* equipo_azul;					/// Nuestro equipo azul
	Equipo* equipo_rojo;					/// Nuestro equipo rojo
	Equipo* equipo_que_lanza;				/// El equipo que lanza (será = equipo_azul o rojo)

	Bolas* conjunto_bolas;					/// Gestión de bolas 
	ElementoDinamico* bola_lanzada;			/// La bola actual?
		
	
	// nuestro "gestor de texturas"
	GLuint _imgBack;
	GLuint _imgExit;
	GLuint _imgPlay;
	GLuint _imgBox[6];
	GLuint _imgBlueTeam;
	GLuint _imgRedTeam;
	GLuint _imgUndetermined;
	GLuint _imgWhiteBall;
	GLuint _imgSoftBall;
	GLuint _imgSemiBall;
	GLuint _imgHardBall;
	GLuint _imgLostRed[7];
	GLuint _imgLostBlue[7];
	GLuint _imgPlus;
	GLuint _imgMinus;
};

#endif // _PARTIDA_H_
